#!/usr/bin/python
"""
A file to generate a setup.py.

mlpack is free software; you may redistribute it and/or modify it under the
terms of the 3-clause BSD license.  You should have received a copy of the
3-clause BSD license along with mlpack.  If not, see
http://www.opensource.org/licenses/BSD-3-Clause for more information.
"""
import os
import sys
import numpy as np
import re
import platform
from pathlib import Path

# Process input argument --module={name} first if needed.
module = None
if "--module=" in sys.argv[-1]:
  module = sys.argv[-1].split('=')[1]
  del sys.argv[-1]

from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext

pyxs='${MLPACK_PYXS}'.split(' ')

if not '${OpenMP_CXX_FLAGS}':
  extra_link_args=[]
else:
  extra_link_args=['${OpenMP_CXX_FLAGS}']

# We'll link with the exact paths to each library using extra_objects, instead
# of linking with 'libraries' and 'library_dirs', because of differences in
# Windows and Linux linking behavior.
libraries = '${MLPACK_LIBRARIES}'.split(' ')

# Workaround: if we receive "m" as a library, what was actually meant was -lm.
for i in range(len(libraries)):
  if libraries[i] == 'm':
    libraries[i] = '-lm'

# Potentially faulty assumption: we can always link against libraries directly
# by just specifying the full path to them on the command line.
extra_link_args += libraries

# Only build the extensions if we are asked to.
if os.getenv('NO_BUILD') == '1':
  modules = []
else:
  cxx_flags = '${CMAKE_CXX_FLAGS}'.strip()
  cxx_flags = re.sub(' +', ' ', cxx_flags)
  extra_cxx_flags = '${EXTRA_CXX_FLAGS}'.strip()
  extra_cxx_flags = re.sub(' +', ' ', cxx_flags)
  cxx_flags += ' '
  cxx_flags += extra_cxx_flags

  extra_args = []
  if platform.system() == 'Windows':
    # Argument specification is different on MSVC, and also use C++17.
    extra_args.extend(['/DBINDING_TYPE=BINDING_TYPE_PYX', '/std:c++17', '/MD',
        '/O2', '/Ob2', '/DNDEBUG'])
  elif platform.system() == 'Darwin':
    extra_args.append('-DBINDING_TYPE=BINDING_TYPE_PYX')
    extra_args.append('-std=c++17')
    # On OS X and Linux, we try to reduce the size of the generated libraries
    # by removing debugging symbols and stripping.
    extra_args.append('-g0')
  else:
    extra_args.append('-DBINDING_TYPE=BINDING_TYPE_PYX')
    extra_args.append('-std=c++17')
    extra_args.append('-g0')
    extra_link_args.append('-Wl,--strip-all')

  if '${OpenMP_CXX_FLAGS}' != '':
    extra_args.append('${OpenMP_CXX_FLAGS}')
  if cxx_flags:
    extra_args.extend(cxx_flags.split(' '))

  # This is used for parallel builds; CMake will set PYX_TO_BUILD accordingly.
  if module is not None:
    modules=[\
        Extension('mlpack.' + name.split('.')[0],
                  ['mlpack/' + name],
                  language='c++',
                  include_dirs=[ \
                      np.get_include(), \
                      '${OUTPUT_DIR}/src/mlpack/bindings/python/'] +
                      '${CYTHON_INCLUDE_DIRECTORIES}'.replace(' ', ';')
                                                     .replace('\;', ' ')
                                                     .split(';'),
                  # CMAKE_CXX_FLAGS seems to have an extra space.
                  extra_compile_args=extra_args,
                  extra_link_args=extra_link_args,
                  define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
                  undef_macros=[] if len("${DISABLE_CFLAGS}") == 0 \
                      else '${DISABLE_CFLAGS}'.split(' ')) \
        for name in pyxs if name == module]
  else:
    modules=[\
        Extension('mlpack.' + name.split('.')[0],
                  ['mlpack/' + name],
                  language='c++',
                  include_dirs=[ \
                      np.get_include(), \
                      '${OUTPUT_DIR}/src/mlpack/bindings/python/'] +
                      '${CYTHON_INCLUDE_DIRECTORIES}'.replace(' ', ';')
                                                     .replace('\;', ' ')
                                                     .split(';'),
                  # CMAKE_CXX_FLAGS seems to have an extra space.
                  extra_compile_args=extra_args,
                  extra_link_args=extra_link_args,
                  define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
                  undef_macros=[] if len("${DISABLE_CFLAGS}") == 0 \
                      else '${DISABLE_CFLAGS}'.split(' ')) \
        for name in pyxs]

# Find all include files.
include_files = []
for (path, directories, filenames) in os.walk('mlpack/include/'):
  for filename in filenames:
    include_files.append(os.path.join('..', path, filename))

setup(name='mlpack',
      version='${PACKAGE_VERSION}',
      description='a flexible, fast machine learning library',
      long_description=Path('setup_readme.md').read_text(encoding='utf-8'),
      long_description_content_type='text/markdown',
      url='http://www.mlpack.org/',
      author='mlpack developers',
      author_email='mlpack@lists.mlpack.org',
      license='BSD',
      classifiers=[
          'Development Status :: 5 - Production/Stable',
          'Intended Audience :: Science/Research',
          'License :: OSI Approved :: BSD License',
          'Topic :: Scientific/Engineering :: Artificial Intelligence',
          'Topic :: Scientific/Engineering :: Mathematics',
          'Topic :: Software Development :: Libraries',
          'Topic :: Software Development :: Libraries :: Application Frameworks'],
      keywords='machine learning, data mining, deep learning, optimization',
      project_urls={
          'Documentation': 'http://www.mlpack.org/doc/mlpack-${PACKAGE_VERSION}/python.html',
          'Source': 'https://github.com/mlpack/mlpack/',
          'Tracker': 'https://github.com/mlpack/mlpack/issues'},
      install_requires=['cython>=0.24', 'numpy', 'pandas'],
      package_dir={ '': '.' }, # Might be superfluous.
      packages=['mlpack'],
      package_data={ 'mlpack': include_files + ['../mlpack/share/pkgconfig/mlpack.pc'] },
      include_package_data=True,
      cmdclass={ 'build_ext': build_ext },
      ext_modules = modules,
      setup_requires=['cython'],
      extras_require={
          "tests": ['pytest>3;python_version>"3.4"', 'pytest>3,<=4.6;python_version<="3.4"'],
      },
      zip_safe = False)
